<?php
declare(strict_types=1);
namespace Framework\Support;
use Framework\Pool\Redis;

/**
 * Support Cache
 *
* // * @property Redis $link
 */

class RedisCache
{

	private $conf = [];
	private $link;
	private $name;

	public function __construct($conf,$name)
	{
		if (!extension_loaded('Redis')) {
			echo 'Redis 扩展没有加载';
			exit();
		}
		$this->name = $name;
		$this->conf = $conf;
        try {
            $this->link = Redis::getInstance($this->conf, $this->name);
        } catch (\Exception $e) {
        }

    }

    public function __call($name, $arguments)
    {
        $data=false;
        try {
            $link = $this->link->getConnection();
            $data = $link->{$name}(...$arguments);
            $this->link->close($link);
        } catch (\RedisException $e) {
            $this->link->close(null);
        }
        return $data;
    }

	public function subscribe($channels,$callback){

        $data=false;
        try {
            $link = $this->link->getConnection();
            $link->setOption(\Redis::OPT_READ_TIMEOUT, '-1');
            $data = $link->subscribe($channels, $callback);
            $link->setOption(\Redis::OPT_READ_TIMEOUT,$this->conf['time_out']);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->subscribe($channels,$callback);
            }
            xn_log('[ subscribe ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

        return $data;
	}


	protected function isBreak($e): bool
	{
		$info = [
			'lost',
		];
		$error = $e->getMessage();
		foreach ($info as $msg) {
			if (false !== stripos($error, $msg)) {
				return true;
			}
		}
		return false;
	}

	public function flushall():bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->flushall();
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->flushall();
            }
            xn_log('[ flushall ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

    public function flushdb():bool
    {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->flushdb();
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->flushdb();
            }
            xn_log('[ flushdb ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r;
    }
    public function info(): array|false
    {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->info();
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->info();
            }
            xn_log('[ info ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r === false ? false : $r;
    }

    public function dbsize():int|false
    {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->dbsize();
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->dbsize();
            }
            xn_log('[ info ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r === false ? 0 : $r;
    }




	public function smembers(string $key):?array
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->SMEMBERS($key);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->SMEMBERS($key);
            }
            xn_log('[ smembers ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r === false ? NULL : $r;

	}


    public function scard(string $key):?int
    {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->scard($key);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->scard($key);
            }
            xn_log('[ scard ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r === false ? NULL : $r;

    }


    public function sadd( string $key,string ...$value):?int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->sadd($key,...$value);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->sadd($key,...$value);
            }
            xn_log('[ sadd ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r === false ? NULL : $r;

	}

    public function SINTER(string $key,string ...$value):?array
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->SINTER($key,...$value);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->SINTER($key,...$value);
            }
            xn_log('[ SINTER ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r === false ? NULL : $r;

	}


    public function SDIFF(string $key,string ...$value):?array
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->SDIFF($key,...$value);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->SDIFF($key,...$value);
            }
            xn_log('[ SDIFF ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r === false ? NULL : $r;

	}

    public function SREM(string $key,string ...$value):?int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->SREM($key,...$value);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->SREM($key,...$value);
            }
            xn_log('[ SREM ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r === false ? NULL : $r;

	}

	//返回所有给定集合的并集
    public function SUNION(string $key,string ...$value):?array
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->SUNION($key,...$value);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->SUNION($key,...$value);
            }
            xn_log('[ SUNION ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r === false ? NULL : $r;

	}


    public function SISMEMBER(string $key,string $value):bool|null
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->SISMEMBER($key,$value);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->SISMEMBER($key,$value);
            }
            xn_log('[ SISMEMBER ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r === false ? NULL : $r;
	}



	public function geopos(string $key = 'geo::user',string ...$member):?array
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->geopos($key, ...$member);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->geopos($key, ...$member);
            }
            xn_log('[ geopos ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

        return $r;

	}

	public function geodist(string $member1,string $member2,string $unit,string $key):?float
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->geodist($key, $member1,$member2,$unit);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->geodist($key, $member1,$member2,$unit);
            }
            xn_log('[ geodist ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

        return $r;

	}

	public function geoadd(float $longitude,float $latitude,string $member,string $key):bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->geoadd($key, $longitude, $latitude, $member);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->geoadd( $longitude, $latitude, $member,$key);
            }
            xn_log('[ geoadd ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
        return $r;

	}

	public function georadius(float $longitude,float $latitude,int $radius ,string $unit = 'km',bool $withdist = true , string $sort ="asc",string $key= 'geo::user'):?array
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->georadius($key, $longitude, $latitude, $radius, $unit, ['withdist' => $withdist, 'sort' => $sort]);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->georadius($longitude, $latitude, $radius, $unit, $withdist, $sort, $key);
            }
            xn_log('[ georadius ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

        return $r;
	}

	public function georadiusbymember(string $member,int $radius = 3,string $unit = 'km',bool $withdist = true, $sort = 'asc', $key = 'geo::user')
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->georadiusbymember($key, $member, $radius, $unit, ['withdist' => $withdist, 'sort' => $sort]);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->georadiusbymember($member, $radius, $unit, $withdist, $sort, $key);
            }
            xn_log('[ georadiusbymember ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}



	public function set(string $k,mixed $v,int $life = 0):bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $_v = is_array($v) ? xn_json_encode($v):$v;
            $opt = [];
            $life && $opt['PXAT']=$life*1000;
            $r = $link->set($k, $_v,$opt);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->set($k, $v, $life);
            }
            xn_log('[ set ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

    /**
     * 设置位图
     * @param $key
     * @param $offset
     * @param $value
     * @param int $time
     * @return int|null
     */

	public function setBit(string $k,int $o,bool $v,int $life = 0):bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->setBit($k, $o,$v);
            $life AND $r AND $link->expire($k, $life);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->setBit($k, $o, $v, $life);
            }
            xn_log('[ setBit ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}


    /**
     * 位图操作
     * @param $operation
     * @param $retKey
     * @param mixed ...$key
     */
	public function bitOp(string $k,string $o,string ...$v):bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->bitOp($k, $o,...$v);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->bitOp($k, $o, ...$v);
            }
            xn_log('[ bitOp ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

    /**
     * 位图操作
     * @param $key
     * @param $bit
     * @param $start
     * @param $end
     */
	public function bitPos(string $key,bool $bit,int $start,int $end = null):int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->bitPos($key, $bit, $start, $end);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->bitPos($key, $bit, $start, $end);
            }
            xn_log('[ bitPos ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}


	public function mset(array $k,int $life = 0):bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $data = [];
            foreach ($k as $_k => $_v){
                $data[$_k] = is_array($_v) ? xn_json_encode($_v):$_v;
            }
            $r = $link->mset($data);
            if($life && $r){
                foreach ($k as $_k => $_v){
                    $link->expire($_k, $life);
                }
            }
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->mset($k, $life);
            }
            xn_log('[ mset ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function hmset(string $k,array $v,int $life = 0):bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->hMSet($k,$v);
            if($life && $r){
                foreach ($k as $_k => $_v){
                    $link->expire($_k, $life);
                }
            }
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->hmset($k, $v);
            }
            xn_log('[ hmset ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function hmget(string $k,array $v):?array {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->hMGet($k,$v);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->hMGet($k,$v);
            }
            xn_log('[ hMGet ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
		return $r;
	}

    public function hdel(string $k,string $v):bool {
        $r=false;
        try {
            $link = $this->link->getConnection();
            if(is_array($v)){
                $r = $link->hDel($k,...$v);
            }else{
                $r = $link->hDel($k,$v);
            }

            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->hdel($k, $v);
            }
            xn_log('[ hdel ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

        return $r;
    }

	public function hgetAll(string $k):?array {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->hGetAll($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->hgetAll($k);
            }
            xn_log('[ hgetAll ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
		return $r;
	}


    public function getBit(string $k,int $o):bool
    {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->getBit($k, $o);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->getBit($k, $o);
            }
            xn_log('[ getBit ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

        return $r;
    }


    public function bitCount(string $k):int
    {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->bitCount($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->bitCount($k);
            }
            xn_log('[ bitCount ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

        return $r;
    }



    public function get(string $k):mixed
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->get($k);
            (!empty($r) &&($r[0]=='{' || $r[0]=='[')) && $r =  xn_json_decode($r);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->get($k);
            }
            xn_log('[ get ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
		return $r;
	}
	public function keys(string $k):array|bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->keys($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->keys($k);
            }
            xn_log('[ keys ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function mGet(array $k,array $def=[]):?array
	{
		if(empty($k)){
			return $def;
		}
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->mget($k);
            foreach ($r as $_k=>$row){
                (!empty($row) && ($row[0]=='{' || $row[0]=='['))  && $r[$_k] = xn_json_decode($row);
            }
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->mget($k);
            }
            xn_log('[ mget ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function ttl(string $k):?int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->ttl($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->ttl($k);
            }
            xn_log('[ ttl ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r === false ? NULL : $r;
	}

	public function inc(string $k, $amount = 1):?int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->incrby($k, $amount);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->inc($k, $amount );
            }
            xn_log('[ inc ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}
	public function pfadd(string $k,array $v):?int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->pfAdd($k,  $v);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->pfAdd($k,  $v);
            }
            xn_log('[ pfAdd ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
		return $r;
	}
	public function pfcount(string $k):?int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->pfCount($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->pfCount($k);
            }
            xn_log('[ pfCount ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }


		return $r;
	}



	public function pfmerge(string $key,array $value):bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->pfMerge($key,$value);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->pfMerge($key,$value);
            }
            xn_log('[ pfMerge ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

    public function hincrby(string $k,int $member,int $amount = 1) :?int
    {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->hIncrBy($k, $member,$amount);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->hincrby($k, $member,$amount);
            }
            xn_log('[ hincrby ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

        return $r;
    }

	public function zincyby(string $k,int $amount ,int$member):?float
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->zIncrBy($k, $amount,$member);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->zincyby($k,$amount,$member);
            }
            xn_log('[ zincyby ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }
		return $r;
	}

	public function zrevrange(string $k,int $start,int $stop):?array {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->zRevRange($k,$start,$stop);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->zrevrange($k,$start,$stop);
            }
            xn_log('[ zrevrange ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function zcard(string $k):?int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->zCard($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->zcard($k);
            }
            xn_log('[ zcard ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function incr(string $k):int|float
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->incr($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->incr($k);
            }
            xn_log('[ incr ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function expire(string $k,int $ttl):bool {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->expire($k,$ttl);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->expire($k,$ttl);
            }
            xn_log('[ expire ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function expireAt(string $k,int $timestamp):bool
    {
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->expireAt($k,$timestamp);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->expireAt($k,$timestamp);
            }
            xn_log('[ expireAt ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}



	public function zscore(string $k,int $member):float|bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->zScore($k,$member);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->zscore($k,$member);
            }
            xn_log('[ zscore ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}





	public function dec(string $k,int $amount = 1):float|int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->decrby($k, $amount);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->dec($k,$amount);
            }
            xn_log('[ dec ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function llen(string $k):int|bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->llen($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->llen($k);
            }
            xn_log('[ llen ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function lpop(string $k):mixed
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->lpop($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->lpop($k);
            }
            xn_log('[ lpop ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}


	public function lrange(string $k,int $start=0,int $end=-1):array
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->lRange($k,$start,$end);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->lrange($k,$start,$end);
            }
            xn_log('[ lrange ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return  $r;
	}

	public function lpush(string $k,mixed $data):int|false
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->lpush($k, $data);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->lpush($k, $data);
            }
            xn_log('[ lpush ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r ? true : false;
	}

	public function rpush(string $k,mixed $data):int|false
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->rpush($k, $data);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->rpush($k, $data);
            }
            xn_log('[ rpush ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}

	public function delete(string $k):bool|int
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->del($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->delete($k);
            }
            xn_log('[ delete ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r;
	}
	public function exists(string $k):bool
	{
        $r=false;
        try {
            $link = $this->link->getConnection();
            $r = $link->exists($k);
            $this->link->close($link);
        } catch (\Exception $e) {
            $this->link->close(null);
            if ($this->isBreak($e)) {
                return $this->exists($k);
            }
            xn_log('[ exists ]:[ ' . $e->getMessage() . ' ]', 'cache_error');
        }

		return $r ? true : false;
	}

	public function getMultiple($keys, $default = null):array{
		return $this->mGet($keys,$default);
	}
	public function setMultiple($keys, $ttl  = 0):bool{
		return $this->mset($keys,$ttl);
	}

	public function deleteMultiple(array $keys):bool{
	    foreach ($keys as $key){
            $this->delete($key);
        }
		return true;
	}

	public function has($k):bool{
		return $this->exists($k);
	}

	public function clear():bool {
		return $this->truncate();
	}

	public function truncate():bool
	{
		return $this->flushdb();
	}

	public function __destruct()
	{
		$this->link = false;
	}
}
?>